<?php

/*
 * 图片类，包括验证码、缩略图、裁剪、水印
 */

class Image extends Base {
	
	/**
	 * 初始化
	 * @access public
	 * @return boolean
	 */
	public function init()
	{
		//gd库检查
		if (FALSE === ($gd_version = $this->gd_version()))
		{
			$this->set_error('未安装gd库！');
			return FALSE;
		}

		if (version_compare($gd_version, '2.0') < 0)
		{
			$this->set_error('需要gd库版本大于2.0！');
			return FALSE;
		}
		
		return TRUE;
	}

	/**
	 * 图片验证码
	 * @param $config array 设置参数
	 * @return boolean or void 失败返回FALSE，成功不返回任何东西
	 */
	public function verify($config = array())
	{
		/*
		 * width 	integer 验证码图片宽度
		 * height	integer 验证码图片高度
		 * length	integer 验证码字符串长度
		 * sized 	integer 字体大小像素
		 * mode 	integer 验证码字符串模式，1数字，2大字母，3大字母加数字，默认数字
		 * name 	string 验证码字段名称，保存如$_SESSION[$name] = md5($string)
		 * font 	string 字体路径
		 * background 	mixed 背景色，默认白色，rgb数组格式，如array(100,100,100) 其他格式一致为随机颜色
		 * color mixed 	字体色，默认黑色，rgb数组格式，如array(100,100,100) 其他格式一致为随机颜色
		 * rotation 	integer 旋转角度 0-90范围
		 */
		$defaults = array(
			'width'      => 80,
			'height'     => 30,
			'length'     => 4,
			'size'       => 20,
			'mode'       => 1,
			'name'       => 'verify',
			'font'       => 'Biometri.ttf',
			'background' => array(255, 255, 255),
			'color'      => array(0, 0, 0),
			'rotation'   => 30
		);

		$config = array_intersect_key($config, $defaults);
		$config = array_merge($defaults, $config);
		$config['mode'] = in_array(intval($config['mode']), array(1,2,3)) ? intval($config['mode']) : 1;
		$config['rotation'] = $config['rotation'] % 90;
		
		if ( ! $config['background'])
		{
			//（随机背景色）
			$config['background'] = array(
				mt_rand(200, 255),
				mt_rand(200, 255),
				mt_rand(200, 255)
			);
		}
		
		//检测字体
		if ( ! file_exists($config['font']))
		{
			$config['font'] = dirname(__FILE__).'/'.$config['font'];
			if ( ! file_exists($config['font']))
			{
				$config['font'] = '';
			}
		}
		
		$text = $this->rand_string($config['length'], $config['mode']);
		
		//DOIT 必要时需要修改
		//$_SESSION[$config['name']] = md5($text);
		$ci = &get_instance();
		$ci->session->set($config['name'], md5(strtolower($text)));

		$im = $this->create('png', $config['width'], $config['height']);
		
		if ( ! $im)
		{
			$this->set_error('创建图像失败！');
			return FALSE;
		}
		
		//背景色
		$backColor = $this->color($im, $config['background'][0], $config['background'][1], $config['background'][2]);
		
		//画一个矩形框，填充背景色
		imagefilledrectangle($im, 0, 0, $config['width'], $config['height'], $backColor);
		
		//字符串颜色
		if ($config['color'])
		{
			$stringColor = $this->color($im, $config['color'][0], $config['color'][1], $config['color'][2]);
		}
		else
		{
			$stringColor = $this->color($im, mt_rand(0,200), mt_rand(0,120), mt_rand(0,120));
		}
		
		$i = 0;
		$x = ($config['width']-($config['size']-5)*$config['length'])/2;
		if ($config['font'])
		{
			for ($i; $i<$config['length']; $i++)
			{
				imagettftext($im, $config['size'], mt_rand(-$config['rotation'], $config['rotation']), $x, mt_rand(($config['height']+$config['size'])/2-5, ($config['height']+$config['size'])/2+5), $stringColor, $config['font'], $text{$i});
				$x += $config['size']-5;
			}
		}
		else
		{
			for ($i; $i<$config['length']; $i++)
			{
				imagestring($im, 5, $x, mt_rand(($config['height']-$config['size'])/2-5, ($config['height']-$config['size'])/2+5), $text{$i}, $stringColor);
				$x += $config['size']-5;
			}
		}
		
		//输出验证码图像
		$this->output($im, 'png');
	}
	
	/**
	 * 裁剪图片
	 * @access public
	 * @param $image 源图片地址
	 * @param $new_image string 保存新图片
	 * @param $width ingeter 裁剪宽度，默认130
	 * @param $height integer 裁剪高度，默认130
	 * @param $x integer 距左上角水平距离，默认0
	 * @param $y integer 距左上角垂直距离，默认0
	 * @param $quality integer 裁剪图片质量，0-100
	 * @return string or boolean 失败返回FALSE，成功返回裁剪图图片的文件地址
	 */
	public function cut($image, $new_image = '', $width = 130, $height = 130, $x = 0, $y = 0, $quality = 85)
	{
		if ( ! file_exists($image))
		{
			$this->set_error('源图片不存在！');
			return FALSE;
		}
		
		if (FALSE===($info = $this->get_info($image)))
		{
			$this->set_error('源图片不是图片！');
			return FALSE;
		}

		$width = min($width, $info['width']);
		$height = min($height, $info['height']);
		
		$image = str_replace('\\', '/', realpath($image));
		
		$src_im = $this->create_from($image);

		if ( ! $src_im)
		{
			$this->set_error('创建源图片图像失败！');
			return FALSE;
		}

		$cut_im = $this->create($info['type'], $width, $height);
		
		if ( ! $cut_im)
		{
			$this->set_error('创建裁剪图像失败！');
			return FALSE;
		}

		if ($info['type'] == 'png')
		{
			imagealphablending($cut_im, FALSE);
			imagesavealpha($cut_im, TRUE);
		}
		
		if (FALSE === imagecopy($cut_im, $src_im, $x, $y, 0, 0, $width, $height))
		{
			$this->set_error('拷贝图像失败！');
			return FALSE;
		}
		
		//保存图片
		$new_image = $new_image ? str_replace('\\', '/', $new_image) : $image;

		if (FALSE === $this->save($cut_im, $info['type'], $new_image, $quality))
		{
			$this->set_error('保存图片失败！');
			return FALSE;
		}
		
		if ( ! file_exists($new_image))
		{
			$this->set_error('裁剪图片失败！');
			return FALSE;
		}
		
		return $new_image;
	}

	/**
	 * 生成缩略图
	 * @access public
	 * @param $image string 原图片文件地址
	 * @param $new_image string 缩略图文件地址
	 * @param $thumb_width integer 缩略图宽度
	 * @param $thumb_height integer 缩略图高度
	 * @param $quality integer 生成缩略图质量
	 * @param $absolute boolean 是否绝对大小
	 * @return string or boolean 失败返回FALSE，成功返回缩略图图片的文件地址
	 */
	public function thumb($image, $new_image = '', $width = 130, $height = 130, $quality = 85, $absolute = TRUE)
	{
		if ( ! file_exists($image))
		{
			$this->set_error('源图片不存在！');
			return FALSE;
		}
		
		$image = str_replace('\\', '/', realpath($image));
		
		//获取原图信息
		if (FALSE === ($info = $this->get_info($image)))
		{
			$this->set_error('源图片不是图片！');
			return FALSE;
		}
		
		$src_width  = $info['width'];
		$src_height = $info['height'];
		$type = $info['type'];
		
		//计算缩放比例，保证图片不变形
		$scale = min($width/$src_width, $height/$src_height);

		if ($scale>=1)
		{
			//超过原图大小不再缩略
			$dst_width   =  $src_width;
			$dst_height  =  $src_height;
		}
		else
		{
			//缩略图尺寸
			$dst_width = $src_width*$scale;
			$dst_height = $src_height*$scale;
		}
		
		//创建源图片图像
		$src_im = $this->create_from($image);
		
		if ( ! $src_im)
		{
			$this->set_error('创建源图片图像失败！');
			return FALSE;
		}

		$create_width = $dst_width;
		$create_height = $dst_height;
		$dst_x = 0;
		$dst_y = 0;
		if ($absolute)
		{
			$create_width = $width;
			$create_height = $height;
			$dst_x = ($create_width - $dst_width) / 2;
			$dst_y = ($create_height - $dst_height) / 2;
		}

		//创建缩略图图像
		$dst_im = $this->create($type, $create_width, $create_height);
		
		if ( ! $dst_im)
		{
			$this->set_error('创建缩略图图像失败！');
			return FALSE;
		}

		//填充背景色
		if ($absolute)
		{
			//只有png可以透明
			if ($type == 'png')
			{
				$bg_color = $this->color($dst_im, 255, 255, 255, 127);
			}
			else
			{
				$bg_color = $this->color($dst_im, 255, 255, 255);
			}

			imagefill($dst_im, 0, 0, $bg_color); //填充背景色
		}

		if ($type == 'png')
		{
			imagealphablending($dst_im, FALSE); //设置图像非混合模式
			imagesavealpha($dst_im, TRUE); //保留图像alpha信息
		}

		//拷贝图像到缩略图
		if (function_exists('imagecopyresampled'))
		{
			if (FALSE === imagecopyresampled($dst_im, $src_im, $dst_x, $dst_y, 0, 0, $dst_width, $dst_height, $src_width, $src_height))
			{
				$this->set_error('拷贝图片失败！');
				return FALSE;
			}
		}
		else
		{
			if (FALSE === imagecopyresized($dst_im, $src_im, $dst_x, $dst_y, 0, 0, $dst_width, $dst_height, $src_width, $src_height))
			{
				$this->set_error('拷贝图片失败！');
				return FALSE;
			}
		}
		
		//对jpeg图形设置隔行扫描
		if ($type=='jpg' || $type=='jpeg')
		{
			imageinterlace($dst_im, 1);
		}
		
		//保存图片
		$new_image = $new_image ? str_replace('\\', '/', $new_image) : $image;
		
		if (FALSE === $this->save($dst_im, $type, $new_image, $quality))
		{
			$this->set_error('保存图片失败！');
			return FALSE;
		}
		
		if ( ! file_exists($new_image))
		{
			$this->set_error('生成缩略图失败！');
			return FALSE;
		}
		
		return $new_image;
	}

	/**
	 * 添加水印
	 * @access public
	 * @param $image string 源图片地址
	 * @param $water string 水印图片地址
	 * @param $new_image string 新文件地址
	 * @param $x integer 距离源图片（大于0左上角）or（小于0右下角）水平方向距离，0为居中
	 * @param $y integer 距离源图片（大于0左上角）or（小于0右下角）垂直方向距离，0为居中
	 * @param $alpha integer 水印透明度
	 * @param $quality integer 保存图片质量
	 * @return string or boolean 失败返回FALSE，成功返回水印图片的文件地址
	 */
	public function water($image, $water, $new_image = '', $x = -20, $y = -20, $alpha = 60, $quality = 85)
	{
		if ( ! file_exists($image))
		{
			$this->set_error('源图片不存在！');
			return FALSE;
		}
		
		if ( ! file_exists($water))
		{
			$this->set_error('水印图片不存在！');
			return FALSE;
		}
		
		$image = str_replace('\\', '/', realpath($image));
		$water = str_replace('\\', '/', realpath($water));
		
		//源图片信息
		if (FALSE === ($image_info = $this->get_info($image)))
		{
			$this->set_error('源图片不是图片！');
			return FALSE;
		}
		
		//水印图片信息
		if (FALSE === ($water_info = $this->get_info($water)))
		{
			$this->set_error('水印不是图片！');
			return FALSE;	
		}
		
		$image_im = $this->create_from($image);

		if ( ! $image_im)
		{
			$this->set_error('创建源图片图像失败！');
			return FALSE;
		}

		if ($image_info['type'] == 'png')
		{
			imagealphablending($image_im, FALSE);
			imagesavealpha($image_im, TRUE);
		}
		
		$water_im = $this->create_from($water);
		
		if ( ! $water_im)
		{
			$this->set_error('创建水印图片图像失败！');
			return FALSE;
		}

		//水印图片位置计算
		if ($x==0)
		{
			$x = ($image_info['width']-$water_info['width'])/2;
		}
		elseif ($x<0)
		{
			$x = $image_info['width']-$water_info['width']-abs($x);
		}
		$x = $x>=0 ? $x : 0;
		
		if ($y==0)
		{
			$y = ($image_info['height']-$water_info['height'])/2;
		}
		elseif ($y<0)
		{
			$y = $image_info['height']-$water_info['height']-abs($y);
		}
		$y = $y>=0 ? $y : 0;
		
		//拷贝水印到图片
		if (FALSE === imagecopymerge($image_im, $water_im, $x, $y, 0, 0, $water_info['width'], $water_info['height'], $alpha))
		{
			$this->set_error('拷贝图像失败！');
			return FALSE;
		}
		
		$new_image = $new_image ? str_replace('\\', '/', $new_image) : $image;

		if (FALSE === $this->save($image_im, $image_info['type'], $new_image, $quality))
		{
			$this->set_error('保存图片失败！');
			return FALSE;
		}
		
		return $new_image;
	}

	/**
	 * 返回图片信息，是图片的话会返回数组信息，否则返回FALSE，只认为jpg,png,gif为图片格式
	 * @access public
	 * @param $image string 图片地址
	 * @return array or boolean
	 */
	public function get_info($image)
	{
		if (FALSE !== ($image_info = @getimagesize($image)))
		{
			//只认为jpg、png、gif为图片格式
			if ($image_info[2] > 3)
			{
				return FALSE;
			}
			
			switch ($image_info[2])
			{
				case 1:
					$type = 'gif';
					break;
				case 2:
					$type = 'jpg';
					break;
				case 3:
					$type = 'png';
					break;
				default:
					break;
			}
			
			$info = array(
				'width' => $image_info[0],
				'height' => $image_info[1],
				'type' => $type,
				'mime' => $image_info['mime']
			);
			
			return $info;
		}
		else
		{
			return FALSE;
		}
	}
	
	/**
	 * 新建空白图像（资源），成功返回图片资源，失败返回FALSE
	 * @access public
	 * @param $type string 图像类型
	 * @param width integet 图像宽度
	 * @param $height integet 图像高度
	 * @return resource or boolean
	 */
	public function create($type = 'png', $width, $height)
	{
		$type = strtolower($type);
		
		//除了gif类型其余可以建立真彩色图像
		if ($type != 'gif' && function_exists('imagecreatetruecolor'))
		{
			$im = imagecreatetruecolor($width, $height);
		}
		else
		{
			$im = imagecreate($width, $height);
		}
		
		if ( ! $im)
		{
			return FALSE;
		}

		return $im;
	}
	
	/**
	 * 从文件新建图像（资源），成功返回图片资源，失败返回FALSE
	 * @access public
	 * @param image string 图片文件地址
	 * @return resource or boolean
	 */
	public function create_from($image)
	{
		if ( FALSE === ($info = $this->get_info($image)))
		{
			return FALSE;
		}
		
		$type = ($info['type'] == 'jpg') ? 'jpeg' : $info['type'];
		
		$fun = 'imagecreatefrom'.$type;

		$im = $fun($image);

		if ( ! $im)
		{
			return FALSE;
		}
		
		return $im;
	}
	
	/**
	 * 已定义的图片格式，调用image方法，将图片资源保存为图片
	 * @access public
	 * @param $im resource 图片资源
	 * @param $type string 图片格式
	 * @param $new_image string 新图片地址
	 * @param $quality integer 保存图片质量，不同版本可能些不同，那么就无效了
	 * @return boolean
	 */
	public function save($im, $type, $filename, $quality = 75)
	{
		$type = $type=='jpg' ? 'jpeg' : $type;

		//imagegif不支持第三个参数
		if ($type == 'gif')
		{
			$quality = NULL;
		}
		elseif ($type == 'png')
		{
			//imagepng从5.1.2之后，第三个参数值范围变为0-9
			if (version_compare(PHP_VERSION, '5.1.2') > 0)
			{
				$quality = floor($quality / 10);
				if ($quality == 10)
				{
					$quality = 9;
				}
			}
		}
		
		$fun = 'image'.$type;

		if (isset($quality))
		{
			return $fun($im, $filename, $quality);
		}
		else
		{
			return $fun($im, $filename);
		}
	}

	/**
	 * 随机字符串
	 * @access public
	 * @param $len integer 返回字符串长度
	 * @param $type integer 返回字符串类型方式
	 * @return string
	 */
	public function rand_string($len = 4, $type = 1)
	{
		$str = '';

		switch($type)
		{
			case 1:
				$chars = str_repeat('0123456789', 3);
				break;
			case 2:
				$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
				break;
			case 3:
				$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ012345679';
				break;
			default :
				$chars = str_repeat('0123456789', 3);
				break;
		}
		
		if($len>10)
		{
			//位数过长重复字符串一定次数
			$chars= $type==1 ? str_repeat($chars, $len) : str_repeat($chars, 5);
		}
		
		//打乱顺序
		$chars = str_shuffle($chars);
		$str = substr($chars, 0, $len);
		
		return $str;
	}


	/**
	 * 输出图像到浏览器
	 * @access public
	 * @param $im resource 图像资源
	 * @param $type string 图像类型
	 * @return void
	 */
	public function output($im, $type = 'png')
	{	
		$type = strtolower($type);
		$type = $type=='jpg' ? 'jpeg' : $type;
		
		//输出图像
		header("Content-type: image/".$type);
		$fun = 'image'.$type;
		$fun($im);
	}
	
	/**
	 * gd库版本，支持gd库返回版本号，否则返回FALSE
	 * @access public
	 * @return string or boolean
	 */
	public function gd_version()
	{
		static $_gd_version;
		
		if (isset($_gd_version))
		{
			return $_gd_version;
		}
		
		//是否安装gd库
		if ( ! function_exists('gd_info'))
		{
			$_gd_version = FALSE;
			return FALSE;
		}
		
		$info = gd_info();
		$_gd_version = preg_replace('/[^0-9\.]/', '', $info['GD Version']);
		return $_gd_version;
	}
	
	/**
	 * 为图像分配颜色
	 * @access public
	 * @param $im resource 图像资源
	 * @param $red integer red值 0-255
	 * @param $green integer green值 0-255
	 * @param $blue integer blue值 0-255
	 * @param $alpha integer 透明度，0不透明 127完全透明
	 * @return integer
	 */
	public function color($im, $red, $green, $blue, $alpha = NULL)
	{
		if (isset($alpha))
		{
			return imagecolorallocatealpha($im, $red, $green, $blue, $alpha);
		}
		else
		{
			return imagecolorallocate($im, $red, $green, $blue);
		}
	}

}